package com.xin.di.uav.common.utils;

/**
 * @author 01406242
 * @date 2022/8/10 17:27
 * @description
 **/

import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Author: oldou
 * Date: 2020/12/23
 * Description:判断两个区域是否重叠、根据两个坐标的经纬度连线判断该线段是否穿过某个区域
 */
public class AreaOverlapCheckUtils {
    /**
     * 判断线是否穿过某个区域
     *
     * @param lineAxisList 两点确定一条直线的坐标集合 {"经度1,纬度1","经度2,纬度2","经度3,纬度3".....}
     * @param AreaAxisList 区域的坐标集合 {"经度1,纬度1","经度2,纬度2","经度3,纬度3".....}
     * @return /
     */
    public static boolean isLineAcrossArea(List<String> lineAxisList, List<String> AreaAxisList) {
        List<Location> locationList1 = new ArrayList<>();
        List<Location> locationList2 = new ArrayList<>();
        /* 线的坐标转换处理*/
        for (String s : lineAxisList) {
            String[] split = s.split(",");
            Location location = new Location(Double.parseDouble(split[0]), Double.parseDouble(split[1]));
            locationList1.add(location);
        }
        /* 区域的坐标转换处理*/
        for (String s : AreaAxisList) {
            String[] split = s.split(",");
            Location location = new Location(Double.parseDouble(split[0]), Double.parseDouble(split[1]));
            locationList2.add(location);
        }
        //获取线的坐标线段
        List<Line> lineList = getLines(locationList1);
        //获取区域的线段
        List<Line> lineList2 = getLines(locationList2);
        //判断是否相交
        boolean isIntersect = isIntersect(lineList, lineList2);
        if (isIntersect) {
            return true;
        }
        //如果不相交判断是否包含-由于没有相交线段只要存在点在多边形内就说明包含
        boolean isPolygonInPolygon = isPolygon1InPolygon2(locationList1, locationList2);
        if (isPolygonInPolygon) {
            return true;
        }
        return false;
    }

    /**
     * 判断根据给定的区域经纬度判断两个区域是否有重叠地方  A
     *
     * @param areaList1 区域一坐标的字符串集合 {"经度1,纬度1","经度2,纬度2","经度3,纬度3".....}
     * @param areaList2 区域二坐标的字符串集合 {"经度1,纬度1","经度2,纬度2","经度3,纬度3".....}
     * @return 是否相交的标识
     */
    public static boolean isCoinCide(List<String> areaList1, List<String> areaList2) {
        List<Location> locationList1 = new ArrayList<>();
        List<Location> locationList2 = new ArrayList<>();
        /* 区域一转换*/
        for (String s : areaList1) {
            String[] split = s.split(",");
            Location location = new Location(Double.parseDouble(split[0]), Double.parseDouble(split[1]));
            locationList1.add(location);
        }
        /* 区域二转换*/
        for (String s : areaList2) {
            String[] split = s.split(",");
            Location location = new Location(Double.parseDouble(split[0]), Double.parseDouble(split[1]));
            locationList2.add(location);
        }
        //获取四边形的线段
        List<Line> lineList = getLines(locationList1);
        //获取三角形的线段
        List<Line> lineList2 = getLines(locationList2);
        //判断是否相交
        boolean isIntersect = isIntersect(lineList, lineList2);
        if (isIntersect) return true;
        //如果不相交判断是否包含-由于没有相交线段只要存在点在多边形内就说明包含
        boolean isPolygonInPolygon = isPolygonInPolygon(locationList1, locationList2);
        if (isPolygonInPolygon) return true;
        return false;
    }

    /**
     * 判断线段是否相交，A的附属方法 B
     *
     * @param locationList  /
     * @param locationList2 /
     * @return /
     */
    private static boolean isPolygonInPolygon(List<Location> locationList, List<Location> locationList2) {
        //判断第一个多边形是否在第二个多边形内
        for (Location location : locationList) {
            boolean isPointInPolygon = isPointInPolygon(location, locationList2);
            if (isPointInPolygon) return true;
        }
        //判断第二个多边形是否在第一个多边形内
        for (Location location : locationList2) {
            boolean isPointInPolygon = isPointInPolygon(location, locationList);
            if (isPointInPolygon) return true;
        }
        return false;
    }

    private static boolean isPolygon1InPolygon2(List<Location> locationList, List<Location> locationList2) {
        //判断第一个多边形是否在第二个多边形内
        for (Location location : locationList) {
            boolean isPointInPolygon = isPointInPolygon(location, locationList2);
            if (isPointInPolygon) return true;
        }
        return false;
    }

    /**
     * 判断点是否在区域内，B的附属方法
     *
     * @param location
     * @param locationList2
     * @return
     */
    public static boolean isPointInPolygon(Location location, List<Location> locationList2) {
        //点是否在多边形内
        GeneralPath path = new GeneralPath();
        //设定多边形起始点
        path.moveTo(locationList2.get(0).getLongitude(), locationList2.get(0).getLatitude());
        for (Location l : locationList2) {
            path.lineTo(l.getLongitude(), l.getLatitude());
        }
        //图像完成，封闭
        path.moveTo(locationList2.get(0).getLongitude(), locationList2.get(0).getLatitude());
        //多边形结束
        path.closePath();
        return path.contains(location.getLongitude(), location.getLatitude());
    }

    /**
     * 判断线段是否相交 A的附属方法
     *
     * @param lineList  /
     * @param lineList2 /
     * @return /
     */
    private static boolean isIntersect(List<Line> lineList, List<Line> lineList2) {
        for (Line line : lineList) {
            for (Line line1 : lineList2) {
                //两条线段是否相交
                boolean b = Line2D.linesIntersect(line.location1.longitude, line.location1.latitude, line.location2.longitude, line.location2.latitude,
                        line1.location1.longitude, line1.location1.latitude, line1.location2.longitude, line1.location2.latitude);
                if (b) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean isIntersect2(double a1x, double a1y, double b1x, double b1y, double a2x, double a2y, double b2x, double b2y) {
        List<Line> lineList = Arrays.asList(new Line(new Location(a1y, a1x), new Location(b1y, b1x)));
        List<Line> lineList2 = Arrays.asList(new Line(new Location(a2y, a2x), new Location(b2y, b2x)));
        return isIntersect(lineList, lineList2);
    }

    /**
     * 根据坐标经纬度获取线的方法
     *
     * @param locationList /
     * @return /
     */
    private static List<Line> getLines(List<Location> locationList) {
        List<Line> lineList = new ArrayList();
        for (int i = 0; i < locationList.size(); i++) {
            if (i < locationList.size() - 1) {
                Location l = locationList.get(i);
                Location l2 = locationList.get(i + 1);
                Line line = new Line(l, l2);
                lineList.add(line);
            } else {
                Location l = locationList.get(i);
                Location l2 = locationList.get(0);
                Line line = new Line(l, l2);
                lineList.add(line);
            }
        }
        return lineList;
    }

    /**
     * 辅助静态类-线
     */
    public static class Line {
        private Location location1;//起点
        private Location location2;//终点

        public Line(Location location1, Location location2) {
            this.location1 = location1;
            this.location2 = location2;
        }

        public Location getLocation1() {
            return location1;
        }

        public void setLocation1(Location location1) {
            this.location1 = location1;
        }

        public Location getLocation2() {
            return location2;
        }

        public void setLocation2(Location location2) {
            this.location2 = location2;
        }

        @Override
        public String toString() {
            return "Line{" +
                    "location1=" + location1 +
                    ", location2=" + location2 +
                    '}';
        }
    }

    /**
     * 辅助静态类-坐标
     */
    public static class Location {

        private double longitude;//经度
        private double latitude;//纬度

        public Location(double longitude, double latitude) {
            this.longitude = longitude;
            this.latitude = latitude;
        }

        public double getLongitude() {
            return longitude;
        }

        public void setLongitude(double longitude) {
            this.longitude = longitude;
        }

        public double getLatitude() {
            return latitude;
        }

        public void setLatitude(double latitude) {
            this.latitude = latitude;
        }

        @Override
        public String toString() {
            return "Location{" +
                    "longitude=" + longitude +
                    ", latitude=" + latitude +
                    '}';
        }
    }
}
